package yuan.zk.Global_lock;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import yuan.zk.node.ZKCreate;
import yuan.zk.watcher.ZKConnectionWatcher;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @version: 1.0
 * @Description: TODO
 * @author: zZmH
 * @date: 2020/09/12 19:02
 */


public class GlobalLock {
    public static final String ip = "192.168.190.128:2181";
    public static final int TIME_OUT = 5000;
    private ZooKeeper zooKeeper;
    CountDownLatch latch = new CountDownLatch(1);
    private static final String LOCK_ROOT_PATH = "/Locks";
    private static final String LOCK_NODE_NAME = "Lock_";
    private String lockPath;
    private Watcher watcher = new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
            if (watchedEvent.getType() == Event.EventType.NodeDeleted) {
                synchronized (this) {
                    watcher.notifyAll();
                }
            }
        }
    };

    public GlobalLock(){
        try {
            zooKeeper = new ZooKeeper(ip, TIME_OUT, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if (event.getType() == Event.EventType.None) {
                        if (event.getState() == Event.KeeperState.SyncConnected) {
                            System.out.println("connected successfully!");
                            latch.countDown();
                        } else if (event.getState() == Event.KeeperState.Disconnected) {
                            System.out.println("shutdown the connection!");

                        } else if (event.getState() == Event.KeeperState.Expired) {
                            System.out.println("session timeout!");
                        } else if (event.getState() == Event.KeeperState.AuthFailed) {
                            System.out.println("authentication failure!");

                        }
                    }
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void lock() throws Exception{

        createLock();
        attemptLock();

    }
    private void createLock() throws Exception{
        Stat stat = zooKeeper.exists(LOCK_ROOT_PATH, null);

        if (stat == null) {
            zooKeeper.create(LOCK_ROOT_PATH, new byte[0],
                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }

        lockPath = zooKeeper.create(LOCK_ROOT_PATH + "/" + LOCK_NODE_NAME, "".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

        System.out.println("创建锁节点： "+lockPath);

    }
    private void attemptLock() throws Exception{

        List<String> children = zooKeeper.getChildren(LOCK_ROOT_PATH, null);
        Collections.sort(children);

        int index = children.indexOf(lockPath.substring(LOCK_ROOT_PATH.length() + 1));
        if (index == 0) {
            System.out.println("获取锁成功！，下面执行业务逻辑操作");
            service();
        }else{
            System.out.println("获取锁失败，等待中。。。");
            String lastPath = children.get(index - 1);
            Stat lastStat = zooKeeper.exists(LOCK_ROOT_PATH + "/" + lastPath,
                    watcher);
            synchronized (watcher) {
                watcher.wait();
            }
            attemptLock();
        }
    }

    private void service() {

    }

    public void unlock() throws KeeperException, InterruptedException {
        zooKeeper.delete(lockPath, -1);
        zooKeeper.close();
        System.out.println("锁释放...");

    }

    public static void main(String[] args) throws Exception {
        GlobalLock lock = new GlobalLock();

        lock.lock();
        Thread.sleep(3000);
        lock.unlock();
    }
}
